﻿using Roton.Memory;
using Roton.ZZT;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Roton.Wrapper
{
    /// <summary>
    /// Adapts IMemory to a Segment object. This is an abstract class.
    /// </summary>
    abstract partial class MemoryWrapper : IMemory
    {
        protected IBoard board;
        protected BoardWrapperProperties boardProperties;
        protected ActDelegate[] elementActCode;
        protected DrawDelegate[] elementDrawCode;
        protected InteractDelegate[] elementInteractCode;
        protected int elementOffset;
        protected ElementWrapperProperties elementProperties;
        protected int elementSize;
        protected ElementType[] elementTypeList;
        protected Heap heap;
        protected Segment segment;
        protected IState state;
        protected StateWrapperProperties stateProperties;
        protected int thingOffset;
        protected ThingWrapperProperties thingProperties;
        protected int thingSize;
        protected IWorld world;
        protected WorldWrapperProperties worldProperties;

        /// <summary>
        /// Get the board interface.
        /// </summary>
        public IBoard Board
        {
            get { return board; }
        }

        /// <summary>
        /// Dump memory.
        /// </summary>
        public byte[] Dump()
        {
            return segment.Dump();
        }

        /// <summary>
        /// Get an element interface for the specified index.
        /// </summary>
        /// <param name="index">Index for the element to get.</param>
        public IElement GetElement(int index)
        {
            return new ElementWrapper(elementOffset + (elementSize * index), segment, elementProperties);
        }

        /// <summary>
        /// Get the Act code for an element.
        /// </summary>
        /// <param name="index">Index of the element.</param>
        /// <returns></returns>
        public ActDelegate GetElementActCode(int index)
        {
            if (index < 0 || index >= elementActCode.Length)
                throw new Exception("Act code out of bounds.");
            return elementActCode[index];
        }

        /// <summary>
        /// Get the Draw code for an element.
        /// </summary>
        /// <param name="index">Index of the element.</param>
        /// <returns></returns>
        public DrawDelegate GetElementDrawCode(int index)
        {
            if (index < 0 || index >= elementDrawCode.Length)
                throw new Exception("Draw code out of bounds.");
            return elementDrawCode[index];
        }

        /// <summary>
        /// Get an element index from type.
        /// </summary>
        /// <param name="type">Type to retrieve.</param>
        public int GetElementIndexFromType(ElementType type)
        {
            int length = elementTypeList.Length;
            for (int i = 0; i < length; i++)
                if (elementTypeList[i] == type)
                    return i;
            return -1;
        }

        /// <summary>
        /// Get the Interact code for an element.
        /// </summary>
        /// <param name="index">Index of the element.</param>
        /// <returns></returns>
        public InteractDelegate GetElementInteractCode(int index)
        {
            if (index < 0 || index >= elementInteractCode.Length)
                throw new Exception("Interact code out of bounds.");
            return elementInteractCode[index];
        }

        /// <summary>
        /// Get an element's type.
        /// </summary>
        /// <param name="index">Index of the element.</param>
        public ElementType GetElementType(int index)
        {
            if (index < 0 || index >= elementTypeList.Length)
                return ElementType.None;
            return elementTypeList[index];
        }

        /// <summary>
        /// Get a thing interface for the specified index.
        /// </summary>
        /// <param name="index">Index for the thing to get.</param>
        public IThing GetThing(int index)
        {
            return new ThingWrapper(thingOffset + (thingSize * index), segment, thingProperties);
        }

        /// <summary>
        /// Get the state interface.
        /// </summary>
        public IState State
        {
            get { return state; }
        }

        /// <summary>
        /// Get the world interface.
        /// </summary>
        public IWorld World
        {
            get { return world; }
        }
    }
}
